package com.zxd.reflect;

import jdk.nashorn.internal.ir.CatchNode;

import java.lang.reflect.*;
import java.util.Arrays;

/**
 * ClassName:Test
 * Package:com.zxd.reflect
 * 此处Junit不能使用是因为类的名字为Test，改成别的即可导入Junit
 * @Date:2023/10/7 19:25
 * @Author:zxde
 */
public class Test {

    /**
     * 反射之于构造器相关
     * @throws Exception
     */
    @org.junit.Test
    public void getAllConstructor() throws Exception {

        Class<?> aClass = Class.forName("com.zxd.reflect.Cat");

        //获取public修饰的构造器
        Constructor[] constructor = aClass.getConstructors();
        //获取所有构造器，declared：意思是声明的
        Constructor[] declaredConstructor = aClass.getDeclaredConstructors();

        //获取public单个构造器（根据构造函数的参数类型进行匹配）
        Constructor<Cat> oneConstruct = (Constructor<Cat>) aClass.getConstructor();
        //获取全部权限修饰符的构造器（根据构造函数的参数类型进行匹配）
        Constructor<Cat> oneDeclaredConstructor = (Constructor<Cat>) aClass.getDeclaredConstructor(String.class, int.class);

        for(Constructor con:constructor){
            String conName = con.getName();
            int modifiers = con.getModifiers();
            TypeVariable[] typeParameters = con.getTypeParameters();
        }

        Arrays.stream(constructor).forEach(System.out::println);


        System.out.println("-------------------------");

        //构造器使用newInstance()方法获取对象
        Cat cat = oneConstruct.newInstance();


        System.out.println("-------------------------");
        //设置暴力反射，尽管构造器被private修饰但是依旧可以newInstance()
        oneDeclaredConstructor.setAccessible(true);
        Cat catMi =  oneDeclaredConstructor.newInstance("小米", 12);
        System.out.println(catMi);
    }


    @org.junit.Test
    public void getFields() throws Exception{
        Class<Chinese> chineseClass = Chinese.class;

        //获取public修饰的成员变量
        Field[] fields = chineseClass.getFields();
        //获取全部成员变量
        Field[] declaredFields = chineseClass.getDeclaredFields();
        //根据名字获取成员变量
        //  Field name = chineseClass.getField("name");
        //不管权限修饰符获取成员变量对象
        Field nameField = chineseClass.getDeclaredField("name");

        //获取参数类型
        Class<?> type = nameField.getType();

        System.out.println("-----------------");
        Chinese chinese = new Chinese();
        nameField.setAccessible(true); //禁止访问检查，尽管name这个字段是私有的也可以访问
        nameField.set(chinese,"小华");

        String name = (String) nameField.get(chinese);
        System.out.println(chinese);
    }

    /**
     * 测试成员方法
     */
    @org.junit.Test
    public void testMethod() throws Exception {
        Chinese chinese = new Chinese();

        Class chineseClass = chinese.getClass();

        //获取public修饰的成员方法
        Method[] methods = chineseClass.getMethods();
        //获取全部成员方法
        Method[] declaredMethods = chineseClass.getDeclaredMethods();
        //获取单个public成员方法
        Method sayChina = chineseClass.getMethod("sayChina");
        Method sayChinaLow = chineseClass.getDeclaredMethod("sayChinaLow");

        System.out.println("---------------------");
        sayChina.invoke(chinese);

        //当方法是private还想执行的时候需要设置为true
        sayChinaLow.setAccessible(true);
        sayChinaLow.invoke(chinese);
    }
}
